package com.lingdong.onlinejudge.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lingdong.onlinejudge.common.ErrorCode;
import com.lingdong.onlinejudge.common.PageRequest;
import com.lingdong.onlinejudge.exception.BusinessException;
import com.lingdong.onlinejudge.mapper.MatchMapper;
import com.lingdong.onlinejudge.mapper.MatchTopicMapper;
import com.lingdong.onlinejudge.mapper.SubmitMapper;
import com.lingdong.onlinejudge.model.dto.topic.*;
import com.lingdong.onlinejudge.model.entity.Match;
import com.lingdong.onlinejudge.model.entity.MatchTopic;
import com.lingdong.onlinejudge.model.entity.Submit;
import com.lingdong.onlinejudge.model.entity.Topic;
import com.lingdong.onlinejudge.model.vo.topic.TopicListVo;
import com.lingdong.onlinejudge.model.vo.topic.TopicVo;
import com.lingdong.onlinejudge.model.vo.user.UserVo;
import com.lingdong.onlinejudge.service.AuthService;
import com.lingdong.onlinejudge.service.TopicService;
import com.lingdong.onlinejudge.mapper.TopicMapper;
import net.sf.jsqlparser.statement.select.Top;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
* @author lzw
*/
@Service
public class TopicServiceImpl extends ServiceImpl<TopicMapper, Topic>
    implements TopicService{


    @Resource
    private TopicMapper topicMapper;

    @Resource
    private MatchTopicMapper matchTopicMapper;

    @Resource
    private AuthService authService;

    @Resource
    private MatchMapper matchMapper;

    @Resource
    private SubmitMapper submitMapper;


    /**
     * 添加题目
     * @param topicAddDto 题目添加Dto
     * @param token token
     * @return 结果
     */
    @Override
    public boolean addTopic(TopicAddDto topicAddDto, String token) {
        if (StringUtils.isAnyBlank(token)){
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }
        String title = topicAddDto.getTitle();
        String content = topicAddDto.getContent();
        String answer = topicAddDto.getAnswer();
        List<JudgeCase> judgeCase = topicAddDto.getJudgeCase();
        JudgeConfig judgeConfig = topicAddDto.getJudgeConfig();
        Integer topicExp = topicAddDto.getTopicExp();
        List<JudgeCase> topicCase = topicAddDto.getTopicCase();
        Integer difficulty = topicAddDto.getDifficulty();
        Integer topicType = topicAddDto.getTopicType();
        Integer topicLanguage = topicAddDto.getTopicLanguage();
        String topicTip = topicAddDto.getTopicTip();
        if (StringUtils.isAnyBlank(title,content)){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        if (StringUtils.isNotBlank(answer) && answer.length() > 8128){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "答案长度过长");
        }
        if (StringUtils.isNotBlank(topicTip) && topicTip.length() > 100){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"提示长度不能超过100");
        }
//        if (judgeCase == null || judgeCase.size() < 1){
//            throw new BusinessException(ErrorCode.PARAMS_ERROR, "题目测试用例不能为空");
//        }
//        if (topicCase == null || topicCase.size() < 1){
//            throw new BusinessException(ErrorCode.PARAMS_ERROR, "题目测试用例不能为空");
//        }
        if (judgeConfig == null || topicExp == null || difficulty == null
                || topicType == null || topicLanguage == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "题目参数不能为空");
        }
        if (topicExp <= 0 || topicExp > 100){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "题目经验范围为1-100");
        }
        if (difficulty <= 0 || difficulty > 100){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "题目难度范围为1-100");
        }
        if (topicType != 0 && topicType != 1){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "题目类型错误");
        }
        if (topicLanguage != 0 && topicLanguage != 1){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "题目语言错误");
        }
        // 获取登录用户
        UserVo userInfo = authService.getUserInfo(token);
        Topic topic = new Topic();
        BeanUtils.copyProperties(topicAddDto, topic);
        topic.setTags(JSONUtil.toJsonStr(topicAddDto.getTags()));
//        topic.setJudgeCase(JSONUtil.toJsonStr(judgeCase));
//        topic.setTopicCase(JSONUtil.toJsonStr(topicCase));
        topic.setJudgeConfig(JSONUtil.toJsonStr(judgeConfig));
        topic.setCreateBy(userInfo.getId());
        boolean save = this.save(topic);
        if (!save){
            throw new BusinessException(ErrorCode.OPERATION_ERROR);
        }
        return true;
    }

    /**
    * 更新题目
    * @param topicUpdateDto 信息
    * @return boolean
    */
    @Override
    public boolean updateTopic(TopicUpdateDto topicUpdateDto) {
        String title = topicUpdateDto.getTitle();
        String content = topicUpdateDto.getContent();
        String answer = topicUpdateDto.getAnswer();
        List<JudgeCase> judgeCase = topicUpdateDto.getJudgeCase();
        JudgeConfig judgeConfig = topicUpdateDto.getJudgeConfig();
        Integer topicExp = topicUpdateDto.getTopicExp();
        List<JudgeCase> topicCase = topicUpdateDto.getTopicCase();
        Integer difficulty = topicUpdateDto.getDifficulty();
        Integer topicType = topicUpdateDto.getTopicType();
        Integer topicLanguage = topicUpdateDto.getTopicLanguage();
        String topicTip = topicUpdateDto.getTopicTip();
        if (StringUtils.isAnyBlank(title,content)){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        if (StringUtils.isNotBlank(answer) && answer.length() > 8128){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "答案长度过长");
        }
        if (StringUtils.isNotBlank(topicTip) && topicTip.length() > 100){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"提示长度不能超过100");
        }
//        if (judgeCase == null || judgeCase.size() < 1){
//            throw new BusinessException(ErrorCode.PARAMS_ERROR, "题目测试用例不能为空");
//        }
//        if (topicCase == null || topicCase.size() < 1){
//            throw new BusinessException(ErrorCode.PARAMS_ERROR, "题目测试用例不能为空");
//        }
        if (judgeConfig == null || topicExp == null || difficulty == null
                || topicType == null || topicLanguage == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "题目参数不能为空");
        }
        if (topicExp <= 0 || topicExp > 100){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "题目经验范围为1-100");
        }
        if (difficulty <= 0 || difficulty > 100){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "题目难度范围为1-100");
        }
        if (topicType != 0 && topicType != 1){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "题目类型错误");
        }
        if (topicLanguage != 0 && topicLanguage != 1){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "题目语言错误");
        }
        // 根据id查询
        QueryWrapper<Topic> topicQueryWrapper = new QueryWrapper<>();
        topicQueryWrapper.eq("id", topicUpdateDto.getId());
        Topic topic = topicMapper.selectOne(topicQueryWrapper);
        // 转换 Json 对象
        topic.setTags(JSONUtil.toJsonStr(topicUpdateDto.getTags()));
//        topic.setJudgeCase(JSONUtil.toJsonStr(judgeCase));
//        topic.setTopicCase(JSONUtil.toJsonStr(topicCase));
        topic.setJudgeConfig(JSONUtil.toJsonStr(judgeConfig));
        int update = topicMapper.updateById(topic);
        if (update == 0){
            throw new BusinessException(ErrorCode.OPERATION_ERROR);
        }
        return true;
    }

    /**
    * 获取题目信息
    * @param id 题目id
    * @param token token
    * @return TopicVo
    */
    @Override
    public TopicVo getTopic(Long id, String token) {
        // 鉴权
        UserVo userInfo = authService.getUserInfo(token);
        // 根据用户权限判断，如果题目关联的比赛未结束，则只允许管理员查询
//        QueryWrapper<MatchTopic> matchTopicQueryWrapper = new QueryWrapper<>();
//        matchTopicQueryWrapper.eq("topic_id", id);
//        MatchTopic matchTopicSum = matchTopicMapper.selectOne(matchTopicQueryWrapper);
//        String userRole = userInfo.getUserRole();
//        // 使用 create_by 字段判断题目是否开放查询 0-开放 1-不开放
//        if (matchTopicSum != null && matchTopicSum.getCreateBy() == 1){
//            if (StringUtils.isBlank(userRole) || "user".equals(userRole)){
//                throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
//            }
//        }
        // 查询题目
        QueryWrapper<Topic> topicQueryWrapper = new QueryWrapper<>();
        topicQueryWrapper.eq("id", id);
        Topic topic = topicMapper.selectOne(topicQueryWrapper);
        if (topic == null){
            throw new BusinessException(ErrorCode.OPERATION_ERROR);
        }
        // 根据当前登录用户和题目id查询提交表,判断当前登录人是否作答
        LambdaQueryWrapper<Submit> submitQueryWrapper = new LambdaQueryWrapper<>();
        submitQueryWrapper.eq(Submit::getCreateBy,userInfo.getId())
                .eq(Submit::getTopicId,topic.getId());
        boolean isSubmit = submitMapper.selectCount(submitQueryWrapper) > 0;
        topic.setSubmitStatus(isSubmit);
        // json数据转换
        TopicVo topicVo = new TopicVo();
        BeanUtils.copyProperties(topic, topicVo);
        try {
            if (topicVo.getTags() != null){
                topicVo.setTags(JSONArray.parseArray(topic.getTags(), String.class));
            }
            topicVo.setJudgeCase(JSONArray.parseArray(topic.getJudgeCase(), JudgeCase.class));
            topicVo.setTopicCase(JSONArray.parseArray(topic.getTopicCase(), JudgeCase.class));
            topicVo.setJudgeConfig(JSONUtil.toBean(topic.getJudgeConfig(), JudgeConfig.class));
        } catch (Exception e) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR);
        }
        return topicVo;
    }

    /**
    * 查询题目列表
    * @param topicName 题目名称
    * @return TopicVo
    */
    @Override
    public List<TopicListVo> queryTopicList(String topicName) {
        QueryWrapper<Topic> topicQueryWrapper = new QueryWrapper<>();
        topicQueryWrapper.like(StringUtils.isNotBlank(topicName),
                "title", topicName);
        List<Topic> topicList = topicMapper.selectList(topicQueryWrapper);
        List<TopicListVo> topicListVoList = new ArrayList<>();
        // 脱敏
        topicList.forEach(topic -> {
            TopicListVo topicListVo = new TopicListVo();
            BeanUtils.copyProperties(topic, topicListVo);
            topicListVoList.add(topicListVo);
        });
        return topicListVoList;
    }

    /**
     * 分页查询题目
     * @param topicQueryDto 题目查询Dto
     * @param token token
     * @return 结果
     */
    @Override
    public Page<TopicVo> queryTopicByPage(TopicQueryDto topicQueryDto, String token) {
        PageRequest page = topicQueryDto.getPage();
        if (page == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        QueryWrapper<Topic> topicQueryWrapper = new QueryWrapper<>();
        topicQueryWrapper.like(StringUtils.isNotBlank(topicQueryDto.getTitle()),
                "title", topicQueryDto.getTitle());
        topicQueryWrapper.eq(topicQueryDto.getTopicLanguage() != null,
                "topic_language", topicQueryDto.getTopicLanguage());
        topicQueryWrapper.eq(topicQueryDto.getDifficulty() != null,
                "difficulty", topicQueryDto.getDifficulty());
        topicQueryWrapper.eq(topicQueryDto.getTopicType() != null,
                "topic_type", topicQueryDto.getTopicType());
        topicQueryWrapper.eq(topicQueryDto.getTopicNumber() != null,
                "topic_number", topicQueryDto.getTopicNumber());
        // 循环添加标签
        if (topicQueryDto.getTags() != null){
            topicQueryDto.getTags().forEach(tag -> {
                // 校验非法字符
                if (tag.contains("[") || tag.contains("]") || tag.contains("\"")){
                    return;
                }
                // 拼接标签
                topicQueryWrapper.like("tags", tag);
            });
        }
        Page<Topic> topicPage = topicMapper.selectPage(
                new Page<>(page.getCurrent(), page.getPageSize()), topicQueryWrapper);
        // 封装属性
        Page<TopicVo> topicVoPage = new Page<>();
        BeanUtils.copyProperties(topicPage, topicVoPage);
        List<TopicVo> topicVoList = new ArrayList<>();
        // 循环
        for (Topic topic : topicPage.getRecords()) {
            TopicVo topicVo = new TopicVo();
            BeanUtils.copyProperties(topic, topicVo);
            try {
                // 鉴权
                UserVo userInfo = authService.getUserInfo(token);
                // 根据用户权限判断，如果题目关联的比赛未结束，则只允许管理员查询
                QueryWrapper<MatchTopic> matchTopicQueryWrapper = new QueryWrapper<>();
                matchTopicQueryWrapper.eq("topic_id", topic.getId());
                MatchTopic matchTopicSum = matchTopicMapper.selectOne(matchTopicQueryWrapper);
                String userRole = userInfo.getUserRole();
                // 使用 create_by 字段判断题目是否开放查询 0-开放 1-不开放
                if (matchTopicSum != null && matchTopicSum.getCreateBy().equals(1L)) {
                    if (StringUtils.isBlank(userRole) || "user".equals(userRole)) {
                        continue;
                    }
                }
                // json数据转换
                if (topicVo.getTags() != null) {
                    topicVo.setTags(JSONArray.parseArray(topic.getTags(), String.class));
                }
                topicVo.setJudgeCase(JSONArray.parseArray(topic.getJudgeCase(), JudgeCase.class));
                topicVo.setTopicCase(JSONArray.parseArray(topic.getTopicCase(), JudgeCase.class));
                topicVo.setJudgeConfig(JSONUtil.toBean(topic.getJudgeConfig(), JudgeConfig.class));
            } catch (Exception e) {
                continue;
            }
            topicVoList.add(topicVo);
        }
        topicVoPage.setRecords(topicVoList);
        return topicVoPage;
    }

    /**
     * 删除题目
     * @param id 题目id id
     * @return 结果
     */
    @Override
    public boolean deleteById(Long id) {
        QueryWrapper<MatchTopic> matchTopicQueryWrapper = new QueryWrapper<>();
        matchTopicQueryWrapper.eq("topic_id", id);
        List<MatchTopic> matchTopics = matchTopicMapper.selectList(matchTopicQueryWrapper);
        if (matchTopics == null || matchTopics.size() == 0){
            throw new BusinessException(ErrorCode.OPERATION_ERROR,"当前题目关联比赛，请先解除关联后删除");
        }
        QueryWrapper<Topic> topicQueryWrapper = new QueryWrapper<>();
        topicQueryWrapper.eq("id", id);
        int delete = topicMapper.delete(topicQueryWrapper);
        if (delete <= 0){
            throw new BusinessException(ErrorCode.OPERATION_ERROR);
        }
        return true;
    }

    /**
     * 绑定题目
     * @param topicBindDto 题目绑定Dto
     * @param token token
     * @return 结果
     */
    @Override
    public boolean bindTopic(TopicBindDto topicBindDto, String token) {
        UserVo userInfo = authService.getUserInfo(token);
        // 参数校验
        if (topicBindDto.getTopicId() == null || topicBindDto.getMatchId() == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 校验题目id
        QueryWrapper<Topic> topicQueryWrapper = new QueryWrapper<>();
        topicQueryWrapper.eq("id", topicBindDto.getTopicId());
        Topic topic = topicMapper.selectOne(topicQueryWrapper);
        if (topic == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"题目无效");
        }
        // 校验比赛id
        QueryWrapper<Match> matchQueryWrapper = new QueryWrapper<>();
        matchQueryWrapper.eq("id", topicBindDto.getMatchId());
        Match match = matchMapper.selectOne(matchQueryWrapper);
        if (match == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"比赛无效");
        }
        if (!topic.getCreateBy().equals(userInfo.getId()) || !match.getCreateBy().equals(userInfo.getId())){
            throw new BusinessException(ErrorCode.FORBIDDEN_ERROR,"当前题目或比赛不属于当前用户,无法越权操作");
        }
        // 比赛时间内不允许进行任何操作
        if (match.getStartTime().getTime() < System.currentTimeMillis()){
            throw new BusinessException(ErrorCode.FORBIDDEN_ERROR,"比赛时间内或比赛后不允许进行此操作");
        }
        // 绑定
        if (topicBindDto.isBind()){
            QueryWrapper<MatchTopic> matchTopicBindQueryWrapper = new QueryWrapper<>();
            matchTopicBindQueryWrapper.eq("topic_id", topicBindDto.getTopicId());
            Long count = matchTopicMapper.selectCount(matchTopicBindQueryWrapper);
            if (count > 0){
                throw new BusinessException(ErrorCode.OPERATION_ERROR,"当前题目已绑定比赛");
            }
            MatchTopic matchTopic = new MatchTopic();
            BeanUtils.copyProperties(topicBindDto, matchTopic);
            // 默认不公开
            matchTopic.setCreateBy(1L);
            int insert = matchTopicMapper.insert(matchTopic);
            if (insert <= 0){
                throw new BusinessException(ErrorCode.OPERATION_ERROR);
            }
            return true;
        }
        QueryWrapper<MatchTopic> matchTopicBindQueryWrapper = new QueryWrapper<>();
        matchTopicBindQueryWrapper.eq("topic_id", topicBindDto.getTopicId());
        matchTopicBindQueryWrapper.eq("match_id", topicBindDto.getMatchId());
        Long count = matchTopicMapper.selectCount(matchTopicBindQueryWrapper);
        if (count <= 0){
            throw new BusinessException(ErrorCode.OPERATION_ERROR,"当前比赛与题目未绑定无法解绑");
        }
        int delete = matchTopicMapper.delete(matchTopicBindQueryWrapper);
        if (delete <= 0){
            throw new BusinessException(ErrorCode.OPERATION_ERROR);
        }
        return true;
    }


}




